/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package edu.yonsei.iwb.sdt.refinement.generator;

import java.util.Vector;
import edu.yonsei.iwb.sdt.algorithm.DCSSearcher;
import edu.yonsei.iwb.sdt.datastructure.tree.BranchingType;
import edu.yonsei.iwb.sdt.datastructure.DecomposeCandidate;
import edu.yonsei.iwb.sdt.datastructure.DecomposeCandidateSet;
import edu.yonsei.iwb.sdt.datastructure.TargetInstance;
import edu.yonsei.iwb.sdt.ontology.PropertyArc;
import edu.yonsei.iwb.sdt.refinement.CardinalityRestrictionRefinement;
import edu.yonsei.iwb.sdt.refinement.ExpandingHistory;
import edu.yonsei.iwb.sdt.refinement.ExpandingHistorySet;
import edu.yonsei.iwb.sdt.refinement.Refinement;
import edu.yonsei.iwb.sdt.refinement.RefinementType;
import edu.yonsei.iwb.sdt.util.SDTLog;
import edu.yonsei.iwb.ts.TSSearch;
import edu.yonsei.iwb.ts.model.ObjectNode;
import java.io.IOException;
import java.lang.String;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author JDK
 */
public class CardinalityRestrictionRefinementMaker extends Thread {

    private Vector<TargetInstance> instanceSet;
    private PropertyArc pa;
    private int standard;
    private Vector<PropertyArc> historyPA;
    private DecomposeCandidateSet dcs;
    private QuantificationRefinementMaker qrm;
    private Hashtable<String, Integer> valueNumTable;

    public CardinalityRestrictionRefinementMaker(Vector<TargetInstance> instanceSet) {
        this.instanceSet = instanceSet;
        this.qrm = new QuantificationRefinementMaker(RefinementType.CARDINALITYRESTRICTION);
    }

    public CardinalityRestrictionRefinementMaker(PropertyArc pa, Hashtable<String, Integer> vnt, int standard, Vector<PropertyArc> history, Vector<TargetInstance> instanceSet, DecomposeCandidateSet dcs) {
        this.instanceSet = instanceSet;
        this.pa = pa;
        this.valueNumTable = vnt;
        this.standard = standard;
        this.historyPA = history;
        this.dcs = dcs;
        this.qrm = new QuantificationRefinementMaker(RefinementType.CARDINALITYRESTRICTION);
    }

    @Override
    public synchronized void run() {
        try {
            long startTime = System.currentTimeMillis();
            SDTLog.log(SDTLog.DETAIL, "# Generating start - CRR : Standard = " + standard + " / Property : " + pa.toString() + "\n");
            boolean gen = decomposeCandidateOfCRR();
            DCSSearcher.FLAGNUM--;
            long endTime = System.currentTimeMillis();
            if (gen) {
                SDTLog.log(SDTLog.DETAIL, "# CRR : Standard = " + standard + " / Property : " + pa.toString() + " is generated..." + ((endTime - startTime) / 1000.0f) + "s)\n");
            } else {
                SDTLog.log(SDTLog.DETAIL, "# - CRR : Standard = " + standard + " / Property : " + pa.toString() + " is NOT generated..." + ((endTime - startTime) / 1000.0f) + "s)\n");
            }
        } catch (IOException ex) {
            Logger.getLogger(CardinalityRestrictionRefinementMaker.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    private boolean decomposeCandidateOfCRR() throws IOException {
        if (historyPA.isEmpty()) {
            Vector<Refinement> refset = this.refinementGenerator(pa, standard);
            if (refset.size() > 1) {
                this.dcs.add(new DecomposeCandidate(refset, pa, RefinementType.CARDINALITYRESTRICTION));
                return true;
            } else {
                return false;
            }
        } else {
            DecomposeCandidateSet newdcs = this.refinementGenerator(pa, standard, historyPA);
            if (newdcs != null) {
                this.dcs.addAll(newdcs);
                return true;
            } else {
                return false;
            }
        }

    }

    public Vector<Refinement> refinementGenerator(PropertyArc pa, int standard) throws IOException {
        Vector<Refinement> rset = new Vector<Refinement>();        
        
        Vector<String> css = this.getStandardSatisfiedInstanceSet(standard);       

        Vector<TargetInstance> sfTIset = new Vector();
        Vector<TargetInstance> cloneSet = new Vector(instanceSet);
        for (int i = 0; i < css.size(); i++) {
            String result = css.get(i);
            for (int k = 0; k < this.instanceSet.size(); k++) {
                TargetInstance ti = this.instanceSet.get(k);
                if (ti.getUri().equals(result)) {
                    sfTIset.add(ti);                    
                    cloneSet.remove(ti);
                }
            }
        }
        

        if (!sfTIset.isEmpty()) {            
            Refinement pref = new CardinalityRestrictionRefinement(standard, ">", pa);
            pref.setInstanceSet(sfTIset);
            rset.add(pref);
        }

        if (!cloneSet.isEmpty()) {            
            Refinement nref = new CardinalityRestrictionRefinement(standard, "<=", pa);
            nref.setBranchingType(BranchingType.NEGATION_TYPE);
            nref.setInstanceSet(cloneSet);
            rset.add(nref);
        }
        return rset;
    }

    public DecomposeCandidateSet refinementGenerator(PropertyArc pa, int standard, Vector<PropertyArc> propertyHistory) throws IOException {
        
        Vector<String> css2 = this.getStandardSatisfiedInstanceSet(standard);

        ExpandingHistorySet ehs = this.qrm.expandingHistoryCounter(propertyHistory, css2);
        DecomposeCandidateSet dcs = new DecomposeCandidateSet();        

        for (int i = 0; i < ehs.size(); i++) {
            ExpandingHistory eh = ehs.get(i);
            Vector<Refinement> refset = new Vector<Refinement>();

            Vector<String> is = eh.getInstanceSet();
            Vector<TargetInstance> cloneSet = new Vector(this.instanceSet);
            Vector<TargetInstance> sfTIset = new Vector();

            for (int j = 0; j < is.size(); j++) {
                String result = is.get(j);
                for (int k = 0; k < this.instanceSet.size(); k++) {
                    TargetInstance ti = this.instanceSet.get(k);
                    if (ti.getUri().equals(result)) {
                        sfTIset.add(ti);                        
                        cloneSet.remove(ti);
                    }
                }
            }

            if (!sfTIset.isEmpty()) {
                Refinement pref = new CardinalityRestrictionRefinement(standard, ">", pa, eh);
                pref.setInstanceSet(sfTIset);
                refset.add(pref);
            }

            if (!cloneSet.isEmpty()) {
                Refinement nref = new CardinalityRestrictionRefinement(standard, "<=", pa, eh);
                nref.setBranchingType(BranchingType.NEGATION_TYPE);
                nref.setInstanceSet(cloneSet);
                refset.add(nref);
            }

            if (refset.size() > 1) {
                DecomposeCandidate dc = new DecomposeCandidate(refset, pa, RefinementType.CARDINALITYRESTRICTION);
                dcs.add(dc);
            }
        }

        return dcs;
    }

    private Vector<String> getStandardSatisfiedInstanceSet(int standard) {
        Vector<String> result = new Vector();
        Enumeration<String> values = valueNumTable.keys();
        while (values.hasMoreElements()) {
            String value = values.nextElement();
            int size = valueNumTable.get(value);
            if (size > standard) {
                result.add(value);
            }
        }
        return result;
    }    
}
